package com.butterfly.hotkey.client.core.collector;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.butterfly.hotkey.client.core.collector.segment.AbstractSegment;
import com.butterfly.hotkey.client.core.config.AppClientProperties;
import com.butterfly.hotkey.core.model.KeyCountModel;
import com.butterfly.hotkey.core.model.KeyModel;
import com.butterfly.hotkey.core.rule.ClientKeyRule;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.LongAdder;

/**
 * 汇总所有Key最近的访问量，先推送给worker，worker直接推送给dashboard
 * 原架构是worker推送给config-center，dashboard监听，改版后弱化config-center的写操作必要性
 * 此收集器是统计key的频次，因为key在hot的时候，没必要向worker推送，访问缓存即可，但需统计真实访问了多少次
 * 时效性不用太高
 *
 * @author butterfly
 * @since 2024/10/30
 */
public class DefaultKeySummaryCollector extends AbstractSegmentCollector<KeyModel, KeyCountModel, DefaultKeySummaryCollector.HitCount> {

    private final AppClientProperties clientProperties;

    public DefaultKeySummaryCollector(AppClientProperties clientProperties) {
        segments = new Segment[]{new Segment(), new Segment()};
        this.clientProperties = clientProperties;
    }

    @Override
    protected Collection<KeyCountModel> convertSegment(Map<String, HitCount> segmentMap) {
        List<KeyCountModel> list = new ArrayList<>();
        for (Map.Entry<String, HitCount> entry : segmentMap.entrySet()) {
            String key = entry.getKey();
            HitCount hitCount = entry.getValue();
            KeyCountModel keyCountModel = new KeyCountModel();
            keyCountModel.setTotalCount(hitCount.totalHitCount.longValue());
            keyCountModel.setRuleKey(key);
            keyCountModel.setHotCount(hitCount.hotHitCount.longValue());
            list.add(keyCountModel);
        }
        return list;
    }

    private class Segment extends AbstractSegment<KeyModel, HitCount> {
        @Override
        public void addKey(KeyModel keyModel) {
            // 添加key访问次数统计，粒度为秒级
            String key = keyModel.getKey();
            boolean hot = keyModel.isHot();

            ClientKeyRule keyRule = clientProperties.findKeyRule(key);
            String now = DateUtil.date().toString();
            String mapKey = StrUtil.join("_", keyRule.getKeyPattern(), now);

            HitCount hitCount = segment.computeIfAbsent(mapKey, v -> new HitCount());
            hitCount.totalHitCount.increment();
            if (hot) {
                hitCount.hotHitCount.increment();
            }
        }
    }

    public static class HitCount {
        private final LongAdder hotHitCount = new LongAdder();
        private final LongAdder totalHitCount = new LongAdder();
    }
}
